package date0605_1;

import java.util.Arrays;

/**
 * 1、实现一个可以容纳任意多个、任意类型元素的容器 
 * 2、这个容器类中的方法是参照 java.util.Collection 接口中定义的方法来定义的
 */
public class Container2 {

	// 定义表示 默认初始容量 的 常量
	private static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

	// 定义表示 容器最大容量 的 常量
	private static final int MAXIMUM_CAPACITY = 1 << 30;

	// 定义表示 默认加载因子 的 常量
	private static final float DEFAULT_LOAD_FACTOR = 0.75f;

	// 定义一个表示 容器内部 数组的某个位置 尚未被使用的 标志
	private static final Object UNUSED = new Object();



	// 声明一个数组类型的引用变量
	private Object[] elements;
	// 声明一个 int 类型的变量用来统计容器中的元素个数
	private int counter; // 既表示当前容器中的元素个数也表示下次添加元素时的位置
	// 声明一个 float 类型的变量用来确定扩容时机
	private float loadFactor;

	public Container2() {
		this( 10 , 0.75F );
	}

	public Container2( int initialCapacity ) {
		this( initialCapacity , 0.75F );
	}

	public Container2( int initialCapacity, float loadFactor ) {
		// 注意这里的 initialCapacity 的取值范围是 [ 0 , MAXIMUM_CAPACITY ]
		if (initialCapacity < 0 || initialCapacity > MAXIMUM_CAPACITY ) {
			// 创建异常实例 ( 创建 RuntimeException 实例 )
			RuntimeException ex = new RuntimeException("初始容量必须是 [ 0 , " + MAXIMUM_CAPACITY + " ] 之间的正整数值");
			throw ex; // 抛出异常实例，导致当前方法立即结束
		}

		if (loadFactor <= 0 || loadFactor >= 1) {
			// 创建异常实例 ( 创建 RuntimeException 实例 )
			RuntimeException ex = new RuntimeException("加载因子必须是 ( 0 , 1 ) 之间的浮点数");
			throw ex; // 抛出异常实例，导致当前方法立即结束
		}

		// 如果前面两个 if 语句块都未进去执行，则会执行后续操作
		this.elements = new Object[initialCapacity]; // 使用默认初始容量创建数组实例
		this.loadFactor = loadFactor; // 保存用户指定的 加载因子
		this.mark(); // 将整个数组中的所有位置都标记为 UNUSED
	}

	
	/**
	 * 将数组中所有的位置都标记为UNUSED：
	 */
	private void mark(){
		Arrays.fill(elements , UNUSED);//将整个elements 数组填充为 UNUSED
	}
	
	/**
	 * 确保容器的容量 ( 实际上是数组容量 ) 足以容纳下一个元素
	 */
	private void ensureCapacity() {
		// 当达到某个条件时，就对容器进行扩容
		if ( counter > elements.length * loadFactor) {
			// 将 原来的数组 的地址 暂存到 temp 变量中
			final Object[] temp = this.elements;
			//扩容方法就是在原来基础上增长约1.5倍
			int newLength = temp.length * 3 / 2 + 1 ;
			if( newLength > MAXIMUM_CAPACITY ) {
				RuntimeException x = new RuntimeException("容器容量超过最大值");
				throw x;//抛出异常实例导致整个方法立即结束
			}
			// 创建新数组 ( 创建一个新的、更大的数组 ) 并将新数组地址赋值到 elements 变量
			this.elements = new Object[ newLength ];
			// 将原数组中的[ 0 , counter ) 之间的元素拷贝到新数组中
			System.arraycopy(temp, 0, elements, 0, counter);
			// 后续就使用新数组 (放弃老数组) 了 ( 因为 elements 变量中存储了 新数组的地址 )
		}
	}

	/**
	 * 将 参数对应的 对象 添加到 容器 中
	 * 
	 * @param element 被添加的元素
	 * @return 当 元素 成功添加到容器 后返回 true ( 因为添加元素导致容器发生了变化 )
	 */
	public boolean add(Object element) {

		// 确保容器内部的数组容量足以容纳新的元素
		ensureCapacity();

		// 将 element 添加到 elements 数组的 counter 处
		elements[counter] = element;
		// 对 counter 执行 自增操作 ( 增加 1 )
		counter++; // 自增之后的值既表示元素个数又表示下次添加元素时的存放位置

		return true;
	}

	/**
	 * 返回容器中的有效元素个数
	 * 
	 * @return
	 */
	public int size() {
		return this.counter;
	}

	/**
	 * 判断当前容器是否为空
	 * 
	 * @return
	 */
	public boolean isEmpty() {
		return counter == 0;
	}

	/**
	 * 清空容器
	 */
	public void clear() {
		this.counter = 0;
		this.mark();
	}
	
	/**
	 * 判断参数指定的对象是否在容器中存在
	 * @param o 需要检查是否在容器中存在的对象
	 * @return 当被检查兑现那个在容器中存在时就返回true，否则就返回false
	 */
	public boolean contains(Object o) {
		
		for(int i=0;i<counter ; i++) {
			//从数组中获取下标i处的元素
			Object e = elements[i];
			if(e == o || (e!=null && e.equals(o) ) ){
				//当return 语句执行后，方法立即结束
				return true;
			}
		}
		
		return false;
	}
	
	
	public Object[] toArray() {
		//将elements数组中的[0,counter)之间的元素 复制到新数组
		Object[] array = Arrays.copyOf(elements, counter);
		return array;
	}
	
	
	
	//为了在toString方法中连接字符串而创建的StringBuilder实例
	private final StringBuilder builder = new StringBuilder();
	
	@Override
	public String toString() {
		
		builder.append("[");
		if(counter>0) {
			for(int i=0; i<counter; i++) {
				//将每个元素的字符串形式追加到builder末尾
				builder.append(elements[i]);
				builder.append(i<counter-1?",":"");
			}
		}
			
		builder.append("]");
		String s = builder.toString();
		//将builder 的 length 设置为 零  是为了下次使用 builder 时，从缓冲区的第一个位置开始存放字符
		builder.setLength(0);//功能上类似与容器的clear方法
		return s;
	}

}
